﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace TK
{
    public partial class CustomSerializer
    {
        object convertValue(object value, Type targetType, Type ownerType, string propertyName)
        {
            try
            {
                value = value != null && targetType.Name.StartsWith("Nullable`") && Nullable.GetUnderlyingType(targetType) == value.GetType()
                    ? Convert.ChangeType(value, Nullable.GetUnderlyingType(targetType))
                    : Convert.ChangeType(value, targetType);
            }
            catch (InvalidCastException e)
            {
                return processException(value, ownerType, propertyName, targetType);
            }
            catch (OverflowException e)
            {
                return processException(value, ownerType, propertyName, targetType);
            }
            return value;
        }
     
        Array convertArray(Array from, Type targetElementType, Type ownerType, string propertyName)
        {
            var newArray = Array.CreateInstance(targetElementType, from.Length);
            for (var i = 0; i < from.Length; i++)
            {
                var value = from.GetValue(i);
                if (value != null)
                {
                    if (value.GetType() != targetElementType)
                        value = convertValue(value, targetElementType, ownerType, propertyName);
                }
                newArray.SetValue(value, i);
            }
            return newArray;
        }

        IList convertList(IList from, Type targetElementType, Type ownerType, string propertyName)
        {
            var targetList = createObject(typeof(List<>).MakeGenericType(targetElementType)) as IList;
            for (var i = 0; i < from.Count; i++)
            {
                var value = from[i];
                if (value != null)
                {
                    if (value.GetType() != targetElementType) value = convertValue(value, targetElementType, ownerType, propertyName);
                }
                targetList.Add(value);
            }
            return targetList;
        }

        internal object processException(object value, Type ownerType, string propertyName, Type targetType)
        {
            switch (settings.ConvertBehavior)
            {
                case CustomSerializerConvertError.Throw:
                    throw new CustomSerializerException(SerializerFailType.ConvertError, value, ownerType.Name + "." + propertyName);
                case CustomSerializerConvertError.CallHandler:
                    if (settings.CustomSerializerConverter != null) return settings.CustomSerializerConverter(value, ownerType, propertyName, targetType);
                    throw new CustomSerializerException(SerializerFailType.ConverterUndefined, value, ownerType.Name + "." + propertyName);
                default:
                    return getDefaultValue(targetType);
            }
        }
    }
}